/**
 * @file         bsc_can_server.h
 * @brief        CAN服务框架 ———— 服务类
 * @note    
 * @author       Jpz(puzhao.jin@hopechart.com, 靳普诏)
 * @data         2022-8-10
 * @version      1.0
 *
 * @par          修改日志
 * <table>
 * <tr><th>Date        <th>Version               <th>Author          <th>Description
 * <tr><td>2022-8-10   <td>1.0                   <td>Jpz             <td>创建初始版本
 * @copyright    杭州鸿泉物联网技术股份有限公司
 */

#ifndef _BSC_CAN_SERVER_H_
#define _BSC_CAN_SERVER_H_

#include "ofc/ofc_types.h"

#include "bsc_can_server/bsc_can_plug.h"
#include "bsc_can_server/bsc_can_device.h"
#include "bsc_can_server/bsc_can_dispatch.h"

#ifdef __cplusplus
extern "C" {
#endif

// ~~~~~~~~~~~~~~~~~~~~~ 通道掩码 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 组件最多支持 5 路can设备的管理
enum TBsCanServerChannelMaskTag
{
    kBsCanServerChannelMaskCh0 = (0x01 << 0),
    kBsCanServerChannelMaskCh1 = (0x01 << 1),
    kBsCanServerChannelMaskCh2 = (0x01 << 2),
    kBsCanServerChannelMaskCh3 = (0x01 << 3),
    kBsCanServerChannelMaskCh4 = (0x01 << 4),
};
typedef enum TBsCanServerChannelMaskTag TBsCanServerChannelMask;

// ~~~~~~~~~~~~~~~~~~~~ 插件类型 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 注册插件时的插件区分
enum TBsCanServerPlugTypeTag
{
    kBsCanServerPlugNormal    = 0,    // 正常插件
    kBsCanServerPlugTimer     = 1,    // 定时器驱动调度（高精度定时插件）

    kBsCanServerPlugTypeMax,
};
typedef enum TBsCanServerPlugTypeTag TBsCanServerPlugType;

// ~~~~~~~~~~~~~~~~~~~~ 定时器触发间隔 ~~~~~~~~~~~~~~~~~~~~~~~~~~~

// 定时器默认值为 kBsCanServerTimerCycle30Ms
enum TBsCanServerTimerCycleTag
{
    kBsCanServerTimerCycle5Ms      = 5,
    kBsCanServerTimerCycle10Ms     = 10,
    kBsCanServerTimerCycle30Ms     = 30,
    kBsCanServerTimerCycle50Ms     = 50,
};
typedef enum TBsCanServerTimerCycleTag TBsCanServerTimerCycle;

// ~~~~~~~~~~~~~~~~~~~~ busoff回调事件 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * 用户事件，busoff、detect事件类型定义. busoff事件中断调用
 * @param *user_param   用户参数指针
 * @param channel       触发的通道号
 * @return 
 */
typedef void (*TBsCanServerDoEvent)(void *user_param, Byte channel);

/**
 * 用户事件，用于发送结果确认(中断调用)
 * @param *user_param   用户参数指针
 * @param channel       触发的通道号
 * @param data_id       数据帧id
 * @param success       发送情况，成功True，失败False
 * @return 
 */
typedef void (*TBsCanServerDoTxConfirm)(void *user_param, Byte channel, UInt32 data_id, Bool success);

typedef struct TBsCanServerOnEventTag TBsCanServerOnEvent;
struct TBsCanServerOnEventTag
{
    union 
    {
        TBsCanServerDoEvent on_busoff_detect;
        TBsCanServerDoTxConfirm on_tx_confirm;
    } method;
    
    void *user_param;
};

// ~~~~~~~~~~~~~~~~~~~~ TBsCanServer类 (单实例) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * 初始化服务框架
 * @return True 初始化成功
           False 初始化失败. 
 * @note 失败后,内部自动释放过程中初始化完成的设备,程序不需要重复调用TBsCanServerDone
 */
Bool TBsCanServerInit(void);

/**
 * 析构服务框架
 * @return 
 */
void TBsCanServerDone(void);


/**
 * 设置RunOnce中事件等待时间  
 * @param timeout   等待时间，单位（tick, 通常等于ms）默认10ms
 * @return
 */
void TBsCanServerSetWaitTime(Int32 timeout);

/**
 * 获取RunOnce中事件等待时间  
 * @return 当前等待时间
 */
UInt32 TBsCanServerGetWaitTime(void);

/**
 * 设置定时器扫描间隔
 * @param timeout 定时器间隔, 默认5ms. 单位, ms.
 * @return >= 0 成功
           <  0 失败
 */
Bool TBsCanServerSetTimerInterval(UInt32 timeout);

/**
 * 执行一次服务,服务线程反复调用
 * @return 
 */
void TBsCanServerRunOnce(void);

/**
 * 设置busoff事件回调(中断触发，函数执行需要立刻结束)
 * @param user_params   用户传参
 * @param method        函数地址
 * @return 
 */
void TBsCanServerSetBusoffEvent(void *user_params, TBsCanServerDoEvent method);

/**
 * 设置侦测事件回调
 * @param user_params   用户传参
 * @param method        函数地址
 * @return 
 */
void TBsCanServerSetDetectEvent(void *user_params, TBsCanServerDoEvent method);

/**
 * 设置发送事件回调(中断触发，函数执行需要立刻结束)
 * @param user_params   用户传参
 * @param method        函数地址
 * @return 
 * @note    
 */
void TBsCanServerSetSendEvent(void *user_params, TBsCanServerDoTxConfirm method);

/**
 * 设置接收事件回调(中断触发，函数执行需要立刻结束)
 * @param user_params   用户传参
 * @param method        函数地址
 * @return 
 * @note    暂无实现
 */
void TBsCanServerSetRecvEvent(void *user_params, TBsCanServerDoEvent method);


// ~~~~~~~~~~~~~~~~~ 插件管理相关 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * 查询服务中插件数量
 * @param plug_type 插件类型（@ref enum TBsCanServerPlugTypeTag）
 * @return 数量
 */
Int32 TBsCanServerPlugCount(UInt8 plug_type);

/**
 * 注册插件列表
 * @param plug_type     插件类型(enum TBsCanServerPlugTypeTag)
 * @param *plug_table   插件列表（const 数组以NULL为结束标志）
 * @return  >=  0       成功，插件个数
 *          <   0       kHccMidCanRegFailed, 插件类型填写错误
 */
Int32 TBsCanServerRegisterPlugTable(UInt8 plug_type, const TBsCanPlug *plug_table);

/**
 * 注销插件列表
 * @param plug_type     插件类型
 * @return 
 */
void TBsCanServerUnregisterPlugTable(UInt8 plug_type);


/**
 * 使能单独插件
 * @param plug_type     插件类别
 * @param plug_index    插件序号
 * @param enable       True:使能，False:关闭
 * @return >= 0 成功
 *         <  0 失败
 * @note:xxxxx
 */
Int32 TBsCanServerSetPlugEnable(UInt8 plug_type, UInt8 plug_index, Bool enable);

/**
 * 当前插件是否使能
 * @param plug_type     插件类别
 * @param plug_index    插件序号
 * @return True:使能，False:关闭
 * @note:xxxxx
 */
Bool TBsCanServerPlugEnabled(UInt8 plug_type, UInt8 plug_index);

/**
 * 获取当前插件的状态
 * @param plug_type     插件类别
 * @param plug_index    插件序号
 * @return  >= 0 插件状态 @ref TBsCanPlugState
 *          <  0 错误码
 * @note:xxxxx
 */
Int32 TBsCanServerPlugState(UInt8 plug_type, UInt8 plug_index);

// ~~~~~~~~~~~~~~~~~ 分发对象管理相关 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
 * 查询服务中分发对象数量
 * @param plug_type 插件类型（@ref enum TBsCanServerPlugTypeTag）
 * @return 数量
 */
Int32 TBsCanServerDispCount(void);

/**
 * 注册插件列表
 * @param *disp_table   分发对象列表（const 数组以NULL为结束标志）
 * @return  >=  0       成功，分发对象个数
 *          <   0       kHccMidCanRegFailed
 * @note 插件列表以 通道掩码(.channel_mask) >= 0x80 项为结束项
 */
Int32 TBsCanServerRegisterDispTable(const TBsCanDispatch *disp_table);

/**
 * 注销分发对象列表
 * @return 
 */
void TBsCanServerUnregisterDispTable(void);

// ~~~~~~~~~~~~~~~~~~ can通道管理 ~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * 获取项目通道数量  
 * @return 通道数量  
 */
UInt8 TBsCanServerChannelCount(void);

/**
 * 判断CAN通道是否打开
 * @param channel： CAN通道号 [0 ~ 4]
 * @return True     已打开
 *         False    未打开
 */
Bool TBsCanServerChannelIsOpen(UInt8 channel);

/**
 * 打开CAN通道
 * @param channel： CAN通道号 [0 ~ 4]
 * @return >= 0      成功
 *         < 0       失败
 */
Int32 TBsCanServerChannelOpen(UInt8 channel);

/**
 * 关闭CAN通道
 * @param channel： CAN通道号 [0 ~ 4]
 * @return
 */
void TBsCanServerChannelClose(UInt8 channel);


/**
 * 获取can总线上的波特率 
 * @param channel   can通道 [0 ~ 4]
 * @return 返回当前can总线上的波特率,失败返回错误码
 */
Int32 TBsCanServerGetBaud(UInt8 channel);

/**
 * 设置can总线上的波特率
 * @param channel   can通道 [0 ~ 4]
 * @param baud      波特率 
 * @return >= 0      成功，返回baud
 *         < 0       失败
 */
Int32 TBsCanServerSetBaud(UInt8 channel, Int32 baud);

/**
 * 通过CAN通道发送数据
 * @param channel： CAN通道（内部不去判断通道号有效性，需要外部提前判断）
 * @param data：    消息地址
 * @param count：   消息数量 
 * @return > 0      成功发送的消息数量 
 *         <= 0     发送失败
 */
Int32 TBsCanServerWriteData(UInt8 channel, const TBsCanData *data, Int32 count);
// 优先发送(不推荐使用)
Int32 TBsCanServerWritePreemptiveData(UInt8 channel, const TBsCanData *data, Int32 count);

/**
 * 设置为自动侦测波特率模式或者正常收发模式
 * @param channel   CAN通道
 * @param detect    True: 自动侦测波特率模式; False: 正常收发模式
 * @return  >=  0   成功；
 *          <   0   失败；
 */
Int32 TBsCanServerBaudDetect(UInt8 channel, Bool detect);

/**
 * 自适应can总线上的波特率
 * @param channel: can通道
 * @return  >=  0   成功；
 *          <   0   失败，错误码（@ref THccMidCanErrorCodeEnum）；
 */
Int32 TBsCanServerBaudAdaptive(UInt8 channel);

/**
 * 等待can总线完成波特率自适应
 * @param channel       CAN通道
 * @param wait_tick     >= 0 标识等待tick值(会造成线程阻塞); < 0 标识一直等待直到波特率适应结束
 * @return > 0  成功，并返回当前已打开的baud率
 *         < 0  失败，波特率适应中 或 等待超时
 */
Int32 TBsCanServerWaitAdaptive(UInt8 channel, Int32 wait_tick);


/**
 * 设置busOff自动恢复模式
 * @param channel   CAN通道
 * @param detect    True: 自动恢复模式; False: 手动恢复模式
 * @return  >=  0   成功；
 *          <   0   失败；
 */
Int32 TBsCanServerAutoRecover(UInt8 channel, Bool auto_recover);

/**
 * 手动将Bus Off状态恢复到正常状态
 * @param channel: 设备通道号
 * @return == 0 成功；
 *         <  0 失败 channel参数错误
 */
Int32 TBsCanServerBusOffRecover(UInt8 channel);

/**
 * 取消当前正在发送的CAN报文
 * @note 对于队列中data_id不为0的报文会产生[TBsCanDeviceOnSent](@ref kBsCanDeviceAttrIdEvtSentIsr)事件
 * @param channel: 设备通道号
 * @return == 0 成功；
 *         <  0 失败 channel参数错误
 */
Int32 TBsCanServerAbortSend(UInt8 channel);

/**
 * 清除发送队列中的所有报文(包括优先发送的数据);
 * @note
 *  1. 仅在BusOff状态下调用有效
 *  2. 对于队列中data_id不为0的报文会产生[TBsCanDeviceOnSent](@ref kBsCanDeviceAttrIdEvtSentIsr)事件
 * @param channel: 设备通道号
 * @return == 0 成功；
 *         <  0 失败 channel参数错误
 */
Int32 TBsCanServerClearSendFifo(UInt8 channel);

/**
 * 获取can通道设备状态 
 * @param channel   通道号
 * @return 比特位方式表示状态位 （@ref TBsCanDeviceStatusMask）
 */
UInt32 TBsCanServerChannelStatus(UInt8 channel);

/**
 * 设置数据发送使能
 * @note 设备默认使能发送
 * @param channel   通道号
 * @param enable False:禁用发送,设备无法发送；True:使能发送,设备允许发送
 * @return 
 */
void TBsCanServerChannelSetTxEnable(UInt8 channel, Bool enable);

/**
 * 获取数据发送是否使能
 * @param channel   通道号
 * @return False:禁用发送,设备无法发送；True:使能发送,设备允许发送
 */
Bool TBsCanServerChannelTxEnable(UInt8 channel);

/**
 * 设置can负载率参数
 * @param window_time    窗口时间，单位：s
 * @param message_bits   每帧消息比特数，单位：bit
 */
void TBsCanServerSetCanLoadRateParam(UInt8 window_time, UInt8 message_bits);

/**
 * 获取can负载率
 * @param channel   通道号
 * @return 负载率：0-100
 * @note 获取负载率前，需要先设置负载率参数(TBsCanServerSetCanLoadRateParam)
 */
UInt8 TBsCanServerGetCanLoadRate(UInt8 channel);

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 服务接口列表 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


/**
 * 查询服务中插件数量
 * @param type 插件类型（@ref enum TBsCanServerPlugTypeTag）
 * @return 服务接口集
 */
IBsCanServerIf *TBsCanServerInterface(UInt8 type);


#ifdef __cplusplus
} // extern "C" {
#endif


#endif // #ifndef _BSC_CAN_SERVER_H_


